table of contents
SHMOP(2) | Руководство программиста Linux | SHMOP(2) |
ИМЯ¶
shmat, shmdt - операции с общей памятью
ОБЗОР¶
#include <sys/types.h> #include <sys/shm.h> void *shmat(int shmid, const void *shmaddr, int shmflg); int shmdt(const void *shmaddr);
ОПИСАНИЕ¶
Вызов shmat() подключает сегмент общей памяти с идентификатором shmid к адресному пространству вызывающего процесса. Адрес подключения, указанный в shmaddr, учитывается следующим образом:
Если значение shmaddr равно NULL, то система выбирает подходящий (неиспользуемый) адрес для подключения сегмента.
Если значение shmaddr не равно NULL, а в shmflg указан флаг SHM_RND, то подключение производится по адресу shmaddr, округлённому до ближайшего значения кратного SHMLBA. В противном случае shmaddr должно быть выровнено по адресу страницы, к которому производится подключение.
Если в shmflg указан флаг SHM_RDONLY, то сегмент подключается для чтения, и вызывающий процесс должен иметь право на чтение этого сегмента. Иначе подключаемый сегмент будет доступен для чтения и записи, и для этого у процесса должны быть соответствующие права. Сегментов, доступных только на запись, быть не может.
В shmflg может быть указан флаг SHM_REMAP (только в Linux) для обозначения того, что отображение сегмента должно замещать любые существующие отображения в диапазоне, начиная с shmaddr и до размера сегмента (обычно выдается ошибка EINVAL, если в этом диапазоне адресов уже есть отображение). В этом случае значение shmaddr не должно быть равно NULL.
Значение brk(2) вызывающего процесса от подключения не изменяется. При завершении работы процесса сегмент будет автоматически отсоединён. Один и тот же сегмент может быть подключён в адресное пространство процесса несколько раз, как только для чтения, так и для чтения-записи.
При успешном выполнении системный вызов shmat() обновляет поля структуры shmid_ds (см. shmctl(2)), связанной с общим сегментом памяти, следующим образом:
- Полю shm_atime присваивается значение текущего времени.
- Значение shm_lpid устанавливается равным идентификатору вызывающего процесса.
- Значение shm_nattch увеличивается на 1.
Вызов shmdt() отключает сегмент общей памяти, находящийся по адресу shmaddr, от адресного пространства вызывающего процесса. Отключаемый сегмент должен быть подключён по адресу shmaddr с помощью вызова shmat().
При успешном выполнении вызов shmdt() обновляет поля структуры shmid_ds, связанной с общим сегментом памяти, следующим образом:
- Полю shm_dtime присваивается значение текущего времени.
- Значение shm_lpid устанавливается равным идентификатору вызывающего процесса.
- Значение shm_nattch уменьшается на 1. Если оно становится равным 0 и сегмент помечен для удаления, то сегмент удаляется.
При вызове fork(2) потомки наследуют подключённые общие сегменты памяти.
При вызове execve(2) все подключённые общие сегменты памяти отключаются.
При вызове _exit(2) все подключённые общие сегменты памяти отключаются.
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ¶
При успешном выполнении shmat() возвращается адрес подключённого общего сегмента памяти; при ошибке возвращается (void *) -1, а в errno содержится код ошибки.
При успешном выполнении shmdt() возвращается 0; при ошибке возвращается -1, а в errno содержится код ошибки.
ОШИБКИ¶
Значения errno, устанавливаемые при возникновении ошибок в shmat():
- EACCES
- Вызывающий процесс не имеет прав для подключения заданного типа и не имеет мандата CAP_IPC_OWNER.
- EINVAL
- Неправильное значение shmid, не выровненное (по границе страницы и не указан SHM_RND) или неправильное значение shmaddr, или невозможно подключить сегмент по адресу shmaddr, или был указан SHM_REMAP, но shmaddr равно NULL.
- ENOMEM
- Невозможно выделить память для дескриптора или страничных таблиц.
Значения errno, устанавливаемые при возникновении ошибок в shmdt():
- EINVAL
- По адресу shmaddr подключённый общий сегмент памяти отсутствует; или значение shmaddr не выровнено по границе страницы.
СООТВЕТСТВИЕ СТАНДАРТАМ¶
SVr4, POSIX.1-2001.
В SVID 3 (или, возможно, более ранних версиях) тип аргумента shmaddr был изменён с char * на const void *, а тип результата shmat() — с char * на void * (в Linux libc4 и libc5 прототипы определены с char *; в glibc2 — void *).
ЗАМЕЧАНИЯ¶
Для улучшения переносимости программ при подключении общего сегмента памяти рекомендуется использовать shmat() с аргументом shmaddr, установленным в NULL. Необходимо учитывать, что сегмент памяти, подключаемый таким способом, в разных процессах может подключаться по разным адресам. Поэтому все указатели в области общей памяти должны быть не абсолютными, а относительными (как правило относительно адреса начала сегмента).
В Linux сегмент общей памяти можно подключить даже если он помечен для удаление. Однако в POSIX.1-2001 об этом ничего не сказано и многие другие реализации это не поддерживают.
На работу shmat() влияют следующие системные параметры:
- SHMLBA
- Коэффициент округления нижней границы адреса сегмента. Должен быть выровнен со страницей. В настоящее время значение SHMLBA равно PAGE_SIZE.
Реализацией не ограничивается максимальное количество общих сегментов памяти на процесс (SHMSEG).
СМОТРИТЕ ТАКЖЕ¶
brk(2), mmap(2), shmctl(2), shmget(2), capabilities(7), shm_overview(7), svipc(7)
2008-06-03 | Linux |